using System;
using Microsoft.Win32;

namespace DeSleeper.Library
{
    public class DotNetVersion
    {
        public decimal SimpleVersion { get; set; }
        public Version CompleteVersion { get; set; }
        public decimal ServicePack { get; set; }

        /// <summary>
        /// Gets information about the most recent version of .NET installed on the local machine.
        /// </summary>
        /// <exception cref="System.Security.SecurityException">Access to key registry keys/values was not allowed.</exception>
        /// <exception cref="UnauthorizedAccessException">Access to key registry keys/values was not allowed.</exception>
        /// <returns>Information about the version of .NET installed on the local machine.</returns>
        public static DotNetVersion GetVersion()
        {
            return getVersion(Registry.LocalMachine);
        }

        /// <summary>
        /// Gets information about the most recent version of .NET installed on a remote machine, using the registry.
        /// </summary>
        /// <param name="machineName">The remote machine.</param>
        /// <remarks>
        /// In order for the version to be retrieved remotely, both the server and client machines must be running 
        /// the remote registry service, and have remote administration enabled. 
        /// </remarks>
        /// <exception cref="System.Security.SecurityException">Access to key registry keys/values was not allowed.</exception>
        /// <exception cref="UnauthorizedAccessException">Access to key registry keys/values was not allowed.</exception>
        /// <returns>Information about the version of .NET installed at the named location.</returns>
        public static DotNetVersion GetVersion(string machineName)
        {
            return getVersion(RegistryKey.OpenRemoteBaseKey(RegistryHive.LocalMachine, machineName));
        }

        private static DotNetVersion getVersion(RegistryKey localMachineKey)
        {
            DotNetVersion version;
            if (tryExtractVersion(
                localMachineKey.OpenSubKey(@"Software\Microsoft\NET Framework Setup\NDP\v3.5\", false),
                3.5m, out version))
                return version;

            if (tryExtractVersion(
                localMachineKey.OpenSubKey(@"Software\Microsoft\NET Framework Setup\NDP\v3.0\", false),
                3.0m, out version))
                return version;

            if (tryExtractVersion(
                localMachineKey.OpenSubKey(@"Software\Microsoft\NET Framework Setup\NDP\v2.0.50727\", false),
                2.0m, out version))
                return version;

            return null;
        }

        private static bool tryExtractVersion(RegistryKey versionKey, decimal simpleVersion, out DotNetVersion version)
        {
            version = null;
            Version completeVersion;
            if (versionKey == null || !tryParseVersion(versionKey.GetValue("Version", "0") as string, out completeVersion))
                return false;

            version = new DotNetVersion
                          {
                              SimpleVersion = simpleVersion,
                              CompleteVersion = completeVersion,
                              ServicePack = (int) versionKey.GetValue("SP", 0)
                          };
            return true;
        }

        private static bool tryParseVersion(string value, out Version version)
        {
            try
            {
                version = new Version(value);
                return true;
            }
            catch (Exception)
            {
                version = null;
                return false;
            }
        }
    }
}